/************************************************************/
/*文档名称：staffing_sys_server.c                           */
/*文档作者：                                                */
/*创建时间：2017.                                           */
/*文档版本：v                                               */
/*文档简介：                                                */
/*文档说明：                                                */
/************************************************************/
#include "staffing_sys.h"


int sockfd;
int acceptfd;
char *errmsg;
struct sockaddr_in serveraddr, clientaddr;
transmsg sr_msg;
pid_t pid;
sqlite3 *db;
socklen_t addrlen = sizeof(struct sockaddr_in);

void do_login()
{
	int nrow;
	int ncolumns;
	char sql[128];
	char **resultp;
	
	//同注册，若用户名不存在，提示错误，否则进行密码验证
	sprintf(sql,"select * from user where name = '%s' and password = '%s';",sr_msg.user.name,sr_msg.user.password);
	if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncolumns,&errmsg)!= SQLITE_OK)
	{
		printf("%s,%d--%s\n",__func__,__LINE__,errmsg);
	}
	if(ncolumns == 0)
	{
		sr_msg.cmd = DO_LOGIN|DO_FAILED;
		sr_msg.user.type = 4;
	}
	else
	{
		sr_msg.cmd = DO_LOGIN;
		sr_msg.user.type = resultp[ncolumns+1][0] - '0';
	}
	if(send(acceptfd,&sr_msg,sizeof(transmsg),0) < 0)
	{
		err_log("Failed to send");
	}
	
}

void do_exit()
{
	if(sr_msg.cmd == DO_EXIT|1)
	{
		close(acceptfd);
		exit(0);
	}
}
/*******************************************/
/* name      : handler                     */
/* parameter : signal number               */
/* funciton  : recycle the source.         */
/*******************************************/
void handler(int sig)
{
	while(waitpid(-1,NULL,WNOHANG) > 0);
}

int callback(void* arg,int ncolumns ,char** f_value,char** f_name)
{
	char sql[128] = {};
	int *type = (int *)arg;
	int result = (int) (*f_value[1] - 48);

	if(*type == ADMIN && result <= ADMIN){
		return -1;
	}else if(*type == ROOT && result == ROOT){
		return -1;
	}

	return 0;
}

/************************************************/
/* name     : do_delete                         */
/* parameter: cmd no, user type                 */
/* funciton : delete user from table            */
/* author   : Raymond                           */
/************************************************/
void do_delete_user(transmsg *msg, sqlite3 *db)
{
	int ret;
	transmsg sdmsg = *msg;
	int type = msg->user.type;
	char sql[128] = {};

	sprintf(sql,"select * from user where no = %d;",msg->info.no);

	ret = sqlite3_exec(db, sql, callback, &type, &errmsg);

	if(ret == SQLITE_ABORT){
		sdmsg.cmd |= DO_ABORD;
	}else if(ret == SQLITE_OK){
		sprintf(sql,"delete from user where no = %d;",msg->info.no);
		if(sqlite3_exec(db, sql,NULL, NULL, &errmsg) != SQLITE_OK){
			sdmsg.cmd |= DO_FAILED;
		}
	}else{
		sdmsg.cmd |= DO_FAILED;
	}

	if(send(acceptfd, &sdmsg, sizeof(transmsg), 0) < 0){
		err_log("send error");
	}
}

/******************************************/
/*name       : do_insert_user             */
/*parameter  : the struct of user info    */
/*funciton   : insert user into talbe     */
/*author     : Raymond                    */
/******************************************/
int do_insert_user(transmsg *msg, sqlite3 *db)
{
	int nrow;
	int ncolumns;
	char **resultp;
	char sql[128] = {0};
	
	sprintf(sql,"select * from user where no = %d;",msg->info.no);
	if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncolumns,&errmsg)!= SQLITE_OK){
		printf("%s,%d--%s\n",__func__,__LINE__,errmsg);
	}
	if(nrow != 0){
		msg->cmd |= DO_EXIST;
		if(send(acceptfd, msg, sizeof(transmsg), 0) < 0){
		err_log("send error");
		}
		return 0;
	}

	sprintf(sql,"insert into user values('%s',%d,'%s','%s',%d,%d,%d,'%s',%lf);",\
			msg->user.name, msg->user.type, msg->user.password, msg->info.addr, msg->info.age, msg->info.level, msg->info.no, msg->info.phone, msg->info.salary);

	if(sqlite3_exec(db, sql,NULL ,NULL ,&errmsg) != SQLITE_OK){
		msg->cmd |= DO_FAILED;
	}
	
	if(send(acceptfd, msg, sizeof(transmsg), 0) < 0){
		err_log("send error");
	}

	return 0;
}

/******************************************/
/* name     : main                        */
/* parameter:                             */
/* funciton : The main funciton.         .*/
/******************************************/
int main(int argc, const char *argv[])
{
	

	if(argc < 3)
	{
		fprintf(stderr,"Usage:%s serverip port.\n",argv[0]);
		return -1;
	}
	
	//open database
	if(sqlite3_open(DATABASE,&db)!= SQLITE_OK)
	{
		printf("%s",sqlite3_errmsg(db));
		return sqlite3_errcode(db);
	}
	else
	{
		puts("Create or open the user information database successfully!");
	}
	
	if(sqlite3_exec(db,"create table if not exists user(name vchar(32),type integer,password \
vchar(32) not null,addr vchar(32),age integer, level integer ,no integer \
primary key not null,phone vchar(32), salary double);",NULL,NULL,&errmsg)!= SQLITE_OK)
	{
		printf("%s-->%d\n",errmsg,__LINE__);
		exit(2);
	}

	//socket
	if(-1 == (sockfd = socket(AF_INET,SOCK_STREAM,0)))
	{
		err_log("Failed to socket");
	}

	//Fill the addr
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr =inet_addr(argv[1]);
	serveraddr.sin_port =htons(atoi(argv[2]));
	
	//bind the sockfd,serveraddr and port
	if(-1 == bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)))
	{
		err_log("Failed to bind");
	}

	//listen
	if(-1 == listen(sockfd,5))
	{
		err_log("Failed to listen");
	}
	
	signal(SIGCHLD,handler);//用于资源回收

	while(1)
	{
		//接受客户端连接后，开启子进程进行处理，主进程关闭套接字描述符
		if((acceptfd = accept(sockfd,(struct sockaddr *)&clientaddr, &addrlen)) < 0)
		{
			err_log("Failed to accept");
		}
		if((pid = fork()) == 0)
		{
			while(1)
			{ 
				if(recv(acceptfd, &sr_msg, sizeof(transmsg), 0) < 0)
				{
					err_log("Failed to recv");
				}
				switch(sr_msg.cmd)
				{
				case DO_LOGIN:                      
					do_login();
					break;
				case DO_EXIT:
					do_exit();
				case DO_ADDADMIN:
				case DO_ADDUSER:
					do_insert_user(&sr_msg, db);
					break;
				case DO_DELETE:
					do_delete_user(&sr_msg, db);
					break;
				default:
					break;
				}
			}

		}
		close(acceptfd);
	}
	
	return 0;
}
